#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define SUPER_START 0   // 超级快起始位置
#define INODE_START 1   // Inode起始数据块位置
#define DATA_START 33   // 数据块起始位置

#define DATA_MAGIC 0x00dec0de   // 幻数

#define INODE_MAP 32    // Inode位图大小 INODE_ALL/int32_t
#define INODE_ALL 1024  // Inode个数
#define INODE_SIZE 32   // Inode大小
#define INODE_ONE_BLOCK 32   // 一个数据块中inode的个数，BLCOK_SIZE/INODE_SIZE
#define INODE_POINT 6   // 数据块指针个数
#define INODE_ROOT_ID 0 // 根inode的id

#define BLOCK_SIZE 1024    // 数据块大小
#define BLOCK_MAP 128   // 数据块位图大小 BLOCK_ALL/int32_t
#define BLOCK_ALL 1024*4    // 数据块个数

#define DIR_SIZE 128    // 目录项大小
#define DIR_ONE_BLOCK 8 // 一个数据块中目录项个数 BLOCK_SIZE/DIR_SIZE
#define DIR_NAME_LEN 121    // 文件名长度

#define F_TYPE_DIR 0    // 目录
#define F_TYPE_FILE 1   // 文件

#define CMD_NAME_LEN 100    // cmd命令长度
#define CMD_MAX_ARGS 5  // cmd最大段数

#define ONLY_INODE 2    // 申请inode
#define ONLY_BLOCK 3    // 申请数据块


// 超级块
typedef struct super_block {
    uint32_t magic_num;         // 幻数，用于识别文件系统
    int32_t free_block_count;   // 空闲的数据块数
    int32_t free_inode_count;   // 空闲索引节点数
    int32_t dir_inode_count;    // 被占用的目录inode数
    uint32_t block_map[BLOCK_MAP];  // 数据块占用位图，记录数据块的使用情况
    uint32_t inode_map[INODE_MAP];  // inode占用位图，记录索引节点表的使用情况
} sp_block;

// inode项
typedef struct inode_item {
    uint32_t size;          // 文件大小
    uint16_t file_type;     // 文件类型（F_TYPE_DIR或F_TYPE_FILE)
    uint16_t link;          // 文件链接数
    uint32_t block_point[INODE_POINT];    //数据块指针，最多6个数据块
} inode_item;

// 目录项
typedef struct dir_item {
    uint32_t inode_id;      // 当前目录项表示的文件/目录对应的inode
    uint16_t valid;         // 当前目录项是否有效
    uint8_t type;           // 目录项类型（F_TYPE_DIR或F_TYPE_FILE)
    char name[DIR_NAME_LEN];    // 目录项表示的文件名
} dir_item;

// 输入命令
typedef struct split {
    int argc;   // 解析个数
    char *argv[CMD_MAX_ARGS];   // 每个解析的字符串结果
} cmds, dirs;

// 初始化和命令实现
void init_filesystem();
void mkdir(cmds* cmd);
void touch(cmds* cmd);
void ls(cmds* cmd);
void cp(cmds* cmd);

// 获取字符串
int getcmd(char* cmd);
void updatecmd(cmds* cmd);

// 命令解析
void print_inode_dir(inode_item inode);
int get_last_inode(char* path, inode_item* last_inode, uint32_t* last_id, uint32_t type);
int get_last_inode_name(char* path, inode_item* last_inode, char* name, uint32_t* last_id);
int get_next_dir_inode(inode_item* inode, char* name, uint32_t* id);
int get_dir_with_name_in_block(uint32_t block_point, char* name, int type, dir_item* dir);
int get_free_in_inode(inode_item* inode, uint32_t* block_num, uint32_t* block_location);
int name_in_inode(inode_item inode, char* name, int type);

// 磁盘中数据获取
int update_sp_block(int type, uint32_t* id);
int reset_sp_block(int type, uint32_t id);
void get_inode_with_id(uint32_t id, inode_item* inode);
void put_inode_with_id(uint32_t id, inode_item* inode);
void data_read_block(unsigned int block_num, char* buf);
void data_write_block(unsigned int block_num, char* buf);

// 结构体生成
uint32_t make_new_dir(inode_item* inode, uint32_t id, char* name, uint32_t type);
void make_inode(inode_item* inode, uint32_t size, uint16_t file_type, uint16_t link, uint32_t* block_point);
void make_dir(dir_item* dir, uint32_t inode_id, uint16_t valid, uint8_t type, char* name);

// 结构体复制
void copy_inode(inode_item* to, inode_item* from);
void copy_dir_item(dir_item* to, dir_item* from);
int copy_block(uint32_t to, uint32_t from);

// 其他
void error(char error_name[]);
void set_int32(uint32_t* map, unsigned int location);
void reset_int32(uint32_t* map, unsigned int location);
uint32_t get_free(uint32_t* map, int len);
void split_with(char* splitchar, char* path, struct split* res);
void flush_in();
void mymemset(uint32_t* dst, int val, int size);
